using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Text;

using Routine.Utilities;

using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.Common.Helpers;
using Styx.Pathing;

using CommonBehaviors.Actions;

using Singular.Dynamics;
using Singular.Helpers;
using Singular.Managers;
using Singular.Settings;

using Action = Styx.TreeSharp.Action;
//
using Rest = Singular.Helpers.Rest;
//
using FarmerJoe.Helpers;



namespace elementalist
{
    public class Routine : CombatRoutine
    {
        /// <summary>
        /// The name of this CombatRoutine
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public override string Name { get { return "elementalist"; } }


        /// <summary>
        /// The <see cref="T:Styx.WoWClass"/> to be used with this routine
        /// </summary>
        /// <value>
        /// The class.
        /// </value>
        public override WoWClass Class { get { return WoWClass.Shaman; } }


        private Composite _combat, _buffs;


        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }

        public DateTime LastCastTime = DateTime.Now;

        public override void Initialize()
        {
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }

		private int addCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.Location) <= 40
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

		private bool IsTargetBoss()
        {
            if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss ||
               (StyxWoW.Me.CurrentTarget.Level >= 90 && StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.MaxHealth > 10000000))
                return true;

            else return false;
        }

		private bool hasAggro()
        {
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if ((StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid) && u.Guid != StyxWoW.Me.Guid && !u.IsFriendly && (u.IsHostile || u.IsNeutral) && !u.IsCritter && u.CurrentTarget.Guid == StyxWoW.Me.Guid) return true;
                //if (u.Guid != StyxWoW.Me.Guid && !u.IsFriendly && (u.IsHostile || u.IsNeutral) && !u.IsCritter && u.CurrentTarget.Guid == StyxWoW.Me.Guid) return true;
            }
            return false;
        }

        private int RAOEaddCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.CurrentTarget.Location) <= 10//&& u.IsWithinMeleeRange
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

        Composite CreateBuffs()
        {
            return new PrioritySelector(
				Cast("Lightning Shield", ret => ! StyxWoW.Me.HasAura("Lightning Shield") && !StyxWoW.Me.Mounted),
/*				new Decorator(ret => StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment.Id != 283,  
					new Sequence( 
						new Action(ctx => Lua.DoString("CancelItemTempEnchantment(1)")),
						Cast("Windfury Weapon")
					)
				),
*/
				Cast("Flametongue Weapon", ret => StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment.Id != 5 && !StyxWoW.Me.Mounted),
				new Decorator(ret =>
					!(StyxWoW.Me.HasAura("Visions of Insanity") || StyxWoW.Me.HasAura("Enhanced Agility")) && !StyxWoW.Me.Mounted,
					new Action(abc =>
					{
						WoWItem item = StyxWoW.Me.BagItems.Find(ret => ret.Name == "Crystal of Insanity"); //ret.Entry == 86569);
                        if (item != null) 
						{
								item.Use();
						}
						else 
						{
							WoWItem item2 = StyxWoW.Me.BagItems.Find(ret => ret.Name == "Alchemist's Flask");
							if (item2 != null) item2.Use();
						}; 
					})
				)
			);
        }

		
		
        Composite CreateCombat()
        {
        return new Decorator(ctz=>(!StyxWoW.Me.IsMoving || StyxWoW.Me.IsMoving) && !StyxWoW.Me.Mounted,
            new PrioritySelector(


                // Interrupt please.
                Cast("Wind Shear", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast),
				Cast("Flametongue Weapon", ret => StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment.Id != 5),
 				Cast("Lightning Shield", ret => !StyxWoW.Me.HasAura("Lightning Shield")),
				Cast("Healing Surge", ret => StyxWoW.Me.HealthPercent < 40),
				Cast("Ancestral Guidance", ret => StyxWoW.Me.HealthPercent < 50),
				Cast("Astral Shift", ret => StyxWoW.Me.HealthPercent < 85),

                new Action(ret => { UseTrinkets(); return RunStatus.Failure; }),
				Cast("Lifeblood"),
				Cast("Blood Fury"),

				//AOE ================
				new Decorator( ret => addCount() > 2,
					new PrioritySelector(
						Spell.CastOnGround("Earthquake", ret => StyxWoW.Me.CurrentTarget.Location, ret=>RAOEaddCount() > 4),
						//Spell.Cast("Magma Totem", ret => StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Magma && t.Unit.Distance < 8 && t.WoWTotem != WoWTotem.FireElemental) == 0 && addCount() > 2),	
						Spell.Cast("Flame Shock", ret => (!StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") ||
							StyxWoW.Me.CurrentTarget.ActiveAuras["Flame Shock"].TimeLeft.TotalSeconds <= 3)),
						Spell.Cast("Lava Burst"),
						Spell.Cast("Elemental Blast"),
						Spell.Cast("Earth Shock", ret => StyxWoW.Me.Auras["Lightning Shield"].StackCount > 6),
						Spell.Cast("Chain Lightning", ret => RAOEaddCount() > 1)
					)
				),
				
				// Normal Rotation
						Spell.Cast("Searing Totem", ret => StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Searing && t.Unit.Distance < 25 && t.WoWTotem != WoWTotem.FireElemental) == 0),	
						Spell.Cast("Stormlash Totem", ret => (StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Stormlash && t.Unit.Distance < 25 && t.WoWTotem != WoWTotem.FireElemental) == 0) && IsTargetBoss()),	
						Spell.Cast("Flame Shock", ret => (!StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") ||
							StyxWoW.Me.CurrentTarget.ActiveAuras["Flame Shock"].TimeLeft.TotalSeconds <= 3)),
						Spell.Cast("Ascendance",ret=>IsTargetBoss()),
						Spell.Cast("Lava Burst"),
						Spell.Cast("Elemental Blast"),
						Spell.Cast("Earth Shock", ret => StyxWoW.Me.Auras["Lightning Shield"].StackCount > 5),
						Spell.Cast("Lightning Bolt")
            )
		);
        }

        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if(firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if(secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret => SpellManager.Cast(spell)));
        }

        public static double TargetDebuffDuration(String spellName)
        {
            return StyxWoW.Me.CurrentTarget.GetAuraTimeLeft(spellName, true).TotalSeconds;
        }

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
    }
}